package com.zc.manager.device.service;

import com.zc.manager.device.domain.IotDevice;
import lombok.AllArgsConstructor;
import com.zc.manager.device.spi.DeviceConfigMetadataSupplier;
import com.zc.core.ProtocolSupports;
import com.zc.core.message.codec.Transport;
import com.zc.core.message.codec.Transports;
import com.zc.core.metadata.ConfigMetadata;
import com.zc.core.metadata.DeviceConfigScope;
import com.zc.core.metadata.DeviceMetadataType;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.function.Function;

@Component
@AllArgsConstructor
public class DefaultDeviceConfigMetadataSupplier implements DeviceConfigMetadataSupplier {

    private final IIotDeviceService instanceService;

    private final IIotProductService productService;

    private final ProtocolSupports protocolSupports;

    @Override
    @SuppressWarnings("all")
    public Flux<ConfigMetadata> getDeviceConfigMetadata(String deviceId) {
        if(StringUtils.isEmpty(deviceId)){
            return Flux.empty();
        }

        return Mono.just(instanceService.getById(deviceId))
            .map(IotDevice::getProductId)
            .flatMapMany(this::getProductConfigMetadata0)
            .filter(metadata -> metadata.hasScope(DeviceConfigScope.device));
    }

    @Override
    public Flux<ConfigMetadata> getDeviceConfigMetadataByProductId(String productId) {
        if(StringUtils.isEmpty(productId)){
            return Flux.empty();
        }
        return getProductConfigMetadata0(productId)
            .filter(metadata -> metadata.hasScope(DeviceConfigScope.device));
    }

    @Override
    public Flux<ConfigMetadata> getProductConfigMetadata(String productId) {
        if(StringUtils.isEmpty(productId)){
            return Flux.empty();
        }
        return getProductConfigMetadata0(productId)
            .filter(metadata -> metadata.hasScope(DeviceConfigScope.product));
    }

    @Override
    @SuppressWarnings("all")
    public Flux<ConfigMetadata> getMetadataExpandsConfig(String productId,
                                                         DeviceMetadataType metadataType,
                                                         String metadataId,
                                                         String typeId) {
        Assert.hasText(productId, "productId can not be empty");
        Assert.notNull(metadataType, "metadataType can not be empty");

        return Mono.just(productService.selectIotProductById(productId))
                .flatMap(product -> {
            return Mono
                    .zip(
                            //消息协议
                            protocolSupports.getProtocol(product.getProtocolId()),
                            //传输协议
                            Mono.justOrEmpty(product.getTransportEnum(Transports.get())),
                            (protocol, transport) -> {
                                return protocol.getMetadataExpandsConfig(transport, metadataType, metadataId, typeId);
                            }
                    );
        })
                .flatMapMany(Function.identity());

    }

    private Flux<ConfigMetadata> getProductConfigMetadata0(String id) {
        return Mono.just(productService.selectIotProductById(id))
                .flatMapMany(product -> protocolSupports
                        .getProtocol(product.getProtocolId())
                        .flatMap(support -> support.getConfigMetadata(Transport.of(product.getTransportProtocol()))));

    }
}
